﻿using System.Configuration;
using System.Globalization;
using System.Linq;
using BlogsAPI.Interfaces;
using Google.Apis.Plus.v1.Data;
using InstaSharp.Models;

namespace BlogsAPI.Sites
{
    using System.Threading;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System.Collections.Generic;
    using BlogsAPI.BlogsYandex;
    using RssToolkit.Rss;
    using System.Web;
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Text.RegularExpressions;
    using Abstract;
    using BlogsAPI.GeoLocation;

    /// <summary>
    /// Статистика по блогеру
    /// </summary>
    [Obsolete()]
    public class GooglePlusStats
    {
        /// <summary>
        /// Идентификатор пользователя
        /// </summary>
        public string Id;
        /// <summary>
        /// Имя блогера
        /// </summary>
        public string Name;
        /// <summary>
        /// Описание
        /// </summary>
        public string About;
        /// <summary>
        /// Число друзей
        /// </summary>
        public uint? Followers = null;
        /// <summary>
        /// Число подписок
        /// </summary>
        public uint? Friends = null;
    }

    /// <summary>
    /// Класс для взаимодействия с крупнейшей социальной сетью Facebook путем доступа через прямое залогинивание!
    /// </summary>
    /// <remarks>Лимит запросов - 60 в минуту</remarks>
    [BlogServiceAPI(Description = "GooglePlus", Link = "https://plus.google.com/")]
    public class GooglePlus : BlogServer, ILike
    {
        /// <summary>
        /// Уникальный ключ для простых запросов
        /// </summary>
        public String[] APIkey = null;//массив из двух ключей, основного и запасного

        #region Regexes

        private static readonly Regex Validation = new Regex(@"^https?://plus\.google\.com/", Regexoptions);
        private static readonly Regex ValidationFull = new Regex(@"^https?://(?:plus|profiles)\.google\.com(?:(?:/u/[0-9]+)?\D([0-9]+)(?:[^0-9]*?|$)|/(\+\w+))", Regexoptions);
        
        /// <summary>
        /// Количество комментариев
        /// </summary>
        static readonly Regex rComments = new Regex(@"""\w+#\d+"",\s*null\s*,""(\d+)"",", Regexoptions);

        /// <summary>
        /// Общее число +1 к посту
        /// </summary>
        static readonly Regex rPlusedTotal = new Regex(@"<div[^<]+data-count\W+(\d+)\W", Regexoptions);
       
        /// <summary>
        /// Сколько человек приплюслвало
        /// </summary>
        static readonly Regex rPlusedComments = new Regex(@"aria-label\W""\+(\d+)\D", Regexoptions);

        /// <summary>
        /// Ссылки количество 
        /// </summary>
        static readonly Regex rLinks = new Regex(@"</content>.{1,100}jsname[^>]+>\s*(\d+)\D", Regexoptions);

        /// <summary>
        /// Определение числа друзей
        /// </summary>
        static readonly Regex rInitData = new Regex(@"\[(\d+),\[\[""", Regexoptions);
        
        /// <summary>
        /// Определение списка друзей
        /// </summary>
        static readonly Regex rData = new Regex(@"\[\[,,\W(\d+)\W[^""]+(\W([^""]+)\W[^\[]+)", Regexoptions);

        /// <summary>
        /// Заголовок
        /// </summary>
        static readonly Regex rMeta = new Regex(@"<meta\s+itemprop\W+(?:name|description)\W+content\W+([^'""]+)", Regexoptions);

        #endregion

        #region interface: BlogServer

        [DebuggerStepThrough]
        public GooglePlus()
        {
            Encoding = Encoding.UTF8;
            if (ConfigurationManager.AppSettings["GooglePlus"] != null)
            {
                APIkey = ConfigurationManager.AppSettings["GooglePlus"].Split(',');
            }
        }

        /// <summary>
        /// http://www.t30p.ru/GooglePlus.aspx
        /// </summary>
        public override bool HasRating
        {
            get { return true; }
        }

        /// <summary>
        /// Создание класса для запросов через API
        /// </summary>
        /// <param name="primarykey"></param>
        /// <param name="secondarykey"></param>
        public GooglePlus(string primarykey, string secondarykey)
        {
            APIkey = new []
                {
                    primarykey,secondarykey
                };
        }

        /// <summary>
        /// проверка, является ли передаваемый урл чатью этого сервиса
        /// </summary>
        public override Boolean ValidateLink(String sLink)
        {
            return Validation.Match(sLink).Success;
        }

        /// <summary>
        /// проверка, является ли передаваемый урл чатью этого сервиса
        /// </summary>
        /// <param name="sLink">ссылка для проверки</param>
        /// <param name="userName">Имя пользователя на блогохостинге</param>
        /// <param name="bType">Тип блога - пользователь или сообщество</param>
        public override Boolean ValidateLink(String sLink, out String userName,out BlogType bType)
        {
            bType = BlogType.Unknown;
            Match m = ValidationFull.Match(sLink);
            if (m.Success)
            {
                bType = BlogType.User;
                if (String.IsNullOrEmpty(m.Groups[1].Value))
                {
                    //https://plus.google.com/+ОксанаГачева/posts
                    //нужно бы получить id...
                    userName = m.Groups[2].Value;
                }
                else
                {
                    //https://*.google.com/profile.php?id=100000869227964
                    userName = m.Groups[1].Value;
                }
            }
            else
            {
                userName = String.Empty;
            }
            return m.Success;
        }

        /// <summary>
        /// Получение ссылки на блог блогера
        /// https://plus.google.com/108978008111493155471/posts
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - пользователь или сообщество</param>
        public override String GetBlogLink(string userName, BlogType btype)
        {
            return String.Format("https://plus.google.com/{0}", userName);
        }

        /// <summary>
        /// Определение числа читателей блога
        /// </summary>
        /// <param name="username">имя</param>
        /// <param name="bt">тип</param>
        /// <returns></returns>
        public override uint? HowManyReaders(string username, BlogType bt)
        {
            return GetStats(username, bt).Followers;
        }

        /// <summary>
        /// Для некоторых блогплатформ можно унифицировать ссылки
        /// Убрать приставку данных из GA и hashtag
        /// </summary>
        /// <param name="link">ссылка на видео</param>
        /// <returns></returns>
        public override String ToCanonicalLink(string link)
        {
            if (String.IsNullOrWhiteSpace(link)) return String.Empty;
            return link.Split(new[] { "?", "#" }, 2, StringSplitOptions.None)[0];
        }

        /// <summary>
        /// Определение числа читателей блога
        /// </summary>
        /// <param name="username">имя</param>
        /// <param name="bt">тип</param>
        /// <returns></returns>
        [Obsolete("Прямой парсинг страницы, вроде как уже не работает")]
        public GooglePlusStats GetStats(string username, BlogType bt = BlogType.User)
        {
            var ret = new GooglePlusStats {Id = username};
            try
            {
                String blogname = GetBlogLink(username, bt);
                HttpWebRequest myHttpWebRequest = MakeRequest(blogname + "/about"); //чтобы меньше грузить
                myHttpWebRequest.Method = "GET"; // метод GET
                //получаем ответ и его разбираем...
                var myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                if (username[0] == '+')
                {
                    //для именных страниц
                    var id = Regex.Match(result, @"id=\W+(\d+)\-about\-", Regexoptions);
                    if (id.Success)
                    {
                        ret.Id = id.Groups[1].Value;
                    }
                }
                MatchCollection m = rMeta.Matches(result);
                foreach (Match match in m)
                {
                    if (match.Groups[0].Value.Contains("\"name\""))
                    {
                        ret.Name = match.Groups[1].Value;
                    }
                    else
                    {
                        ret.About = match.Groups[1].Value;
                    }
                }
                //ПОЛУЧИЛИ xml - откроемка его...
                m = rInitData.Matches(result);
                if (m.Count > 1)
                {
                    ret.Followers = uint.Parse(m[1].Groups[1].Value); //самое первое совпадение(!)
                    ret.Friends = uint.Parse(m[0].Groups[1].Value); //самое первое совпадение(!)
                }
            }
            catch (WebException eBad)
            {
                var resp = (eBad.Response as HttpWebResponse);
                Debug.Write(resp);
            }
            catch (Exception e1)
            {
                Debug.WriteLine("Ошибка загрузки числа читателей: " + e1.Message);
            }
            return ret;
        }

        #endregion

        #region interface: IPosts

        /// <summary>
        /// Залогинивание пользователя в ЖЖ
        /// Однако для постинга-комментинга она не используется
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        /// <remarks>https://accounts.google.com/ServiceLogin?service=oz&continue=https://plus.google.com/</remarks>
        [Obsolete("Not working!")]
        public override bool LogInto(UserAccount user)
        {
            if (_isLoggedIn) return true;
            HttpWebRequest myHttpWebRequest = MakeRequest("https://accounts.google.com/ServiceLogin?service=oz&continue=https://plus.google.com/");
            myHttpWebRequest.Method = "GET";
            myHttpWebRequest.Referer = "https://accounts.google.com/";

            HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
            //получаем ответ
#if DEBUG
            string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
#endif
            myHttpWebResponse.Close();

            CookieParse(myHttpWebResponse.Headers[HttpResponseHeader.SetCookie]);

            myHttpWebRequest = MakeRequest("https://accounts.google.com/ServiceLoginAuth");
            myHttpWebRequest.Method = "POST";
            myHttpWebRequest.Referer = "https://accounts.google.com";
            myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
            ///////////////////////////
            myHttpWebRequest.AllowAutoRedirect = false;
            //из куки нужно извлечь GALX и добавить в параметры
            string GALX = new Regex(@"GALX\S+(?=\s|$)").Match(sCookie).Groups[0].Value;
            // передаем параметры
            string sQueryString = String.Format("Email={0}&Passwd={1}&pstMsg=1&continue=https%3A%2F%2Fplus.google.com%2F&service=oz&PersistentCookie=yes&rmShown=1&{2}",
                //  pstMsg=1&dnConn=https%3A%2F%2Faccounts.youtube.com&continue=https%3A%2F%2Fplus.google.com%2F&service=oz&dsh=-1644848344981749099&timeStmp=&secTok=&GALX=XJZ28RoEErw&Email=magictop30%40gmail.com&Passwd=qQwklopq&PersistentCookie=yes&rmShown=1&signIn=%D0%92%D0%BE%D0%B9%D1%82%D0%B8&asts=
                HttpUtility.UrlEncode(user.username),
                HttpUtility.UrlEncode(user.password),
                GALX
                );
            //***************//
            byte[] byteArr = Encoding.GetBytes(sQueryString);
            myHttpWebRequest.ContentLength = byteArr.Length;
            myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
            myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
            //получаем ответ
#if DEBUG
            result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
#endif
            myHttpWebResponse.Close();
            if (!String.IsNullOrEmpty(myHttpWebResponse.Headers[HttpResponseHeader.SetCookie]))
            {
                //должны были получить ответ с нужными куками
                CookieParse(myHttpWebResponse.Headers[HttpResponseHeader.SetCookie]);
                Log("LogInto " + user + " gains cookie = " + sCookie);
            }
            //
            _isLoggedIn = !String.IsNullOrEmpty(sCookie) && sCookie.Contains("SSID")
                && sCookie.Contains("SID") && sCookie.Contains("LSID");
            if (_isLoggedIn)
            {
                LoggedInAs = user;
            }
            return _isLoggedIn;
        }
        
        /// <summary>
        /// Нажатие кнопки +1 на ссылку
        /// </summary>
        /// <param name="LinkTo">ссылка на страницу</param>
        /// <param name="plusone">плюсуем или удаляем плюс</param>
        /// <remarks>https://ssl.gstatic.com/webclient/js/gc/23803279-4555db52/googleapis.client__iframes-styles-bubble-internal.js</remarks>
        /// <remarks>developerKey:"AIzaSyCKSbrvQasunBoV16zDH9R33D88CeLr9gQ"</remarks>
        /// <remarks>PVT == OriginToken</remarks>
        /// <remarks>[{"method":"pos.plusones.insert","id":"pos.plusones.insert","params":{"cdx":"252936","id":"http://topbloger.livejournal.com/7707749.html","source":"widget","userId":"@viewer","groupId":"@self"},"jsonrpc":"2.0","key":"pos.plusones.insert","apiVersion":"v1"}]</remarks>
        /// <returns>TRUE если нажатие прошло успешно</returns>
        [Obsolete("Not working!")]
        public Boolean SetPlusOne(Uri LinkTo, Boolean plusone)
        {
            if (LoggedInAs == null) return false;
            try
            {
                string DeveloperKey = "AIzaSyCKSbrvQasunBoV16zDH9R33D88CeLr9gQ";
                HttpWebRequest myHttpWebRequest =
                    MakeRequest(String.Format("https://plusone.google.com/u/0/_/+1/fastbutton?url={0}&size=medium&count=true&annotation=&hl=ru&jsh=r%3Bgc%2F23803279-4555db52",
                    HttpUtility.UrlEncode(LinkTo.OriginalString)));
                myHttpWebRequest.Method = "GET";
                myHttpWebRequest.Referer = "https://plusone.google.com/";

                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
                myHttpWebResponse.Close();
                //
                string OriginToken = new Regex(@"_PVT[^']+'([^']+)", Regexoptions).Match(result).Groups[1].Value;
                //
                myHttpWebRequest = MakeRequest("https://clients6.google.com/rpc?key="+DeveloperKey);
                myHttpWebRequest.Method = "POST";
                myHttpWebRequest.ContentType = "application/json; charset=UTF-8";
                myHttpWebRequest.Referer = "https://plusone.google.com";
                // передаем параметры
                string sQueryString =
                    "[{\"method\":\"pos.plusones.insert\",\"id\":\"pos.plusones."+(plusone?"insert":"delete")+"\",\"params\":{\"cdx\":\"252936\",\"id\":\"" +
                    LinkTo.OriginalString +
                    "\",\"source\":\"widget\",\"userId\":\"@viewer\",\"groupId\":\"@self\"},\"jsonrpc\":\"2.0\",\"key\":\"pos.plusones."+(plusone?"insert":"delete")+"\",\"apiVersion\":\"v1\"}]";
                //***************//
                byte[] byteArr = Encoding.GetBytes(sQueryString);
                myHttpWebRequest.ContentLength = byteArr.Length;
                myHttpWebRequest.GetRequestStream().Write(byteArr, 0, byteArr.Length);
                myHttpWebRequest.Headers.Add("OriginToken",OriginToken);
                myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //получаем ответ
#if DEBUG
                result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding).ReadToEnd();
#endif
                myHttpWebResponse.Close();
                return true;
            }catch(Exception e1)
            {
                Debug.WriteLine(e1.Message);
            }
            return false;
        }

        #endregion

        #region interface: IData Функционал экспорта данных

        public override BlogPost GetOnePost(string linkOnPost, string userName, BlogType btype)
        {
            return base.GetOnePost(linkOnPost.Replace("http:","https:"), userName, btype);//там все ссылки в Https
        }
        
        /// <summary>
        /// Получение ссылки на RSS блогера,
        /// Сейчас нету нормального RSS
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">тип блога</param>
        /// <remarks>http://mashable.com/2011/07/17/google-plus-rss-feed/</remarks>
        /// <remarks>https://plus.google.com/104961845171318028721/posts/DamjzZBVxd7</remarks>
        public override String GetRssLink(string userName, BlogType btype)
        {
            //g.t30p.ru
            return String.Format("http://tools.t30p.ru/g.aspx?{0}", userName);
        }

        /// <summary>
        /// Получение числв комментов путем ручного парсинга страницы
        /// </summary>
        /// <param name="postlink">ссылка на пост</param>
        /// <returns>число комментов к записи</returns>
        public PostStats GetPostStats(Uri postlink)
        {
            var ps = new PostStats();
            try
            {
                string result = String.Empty;
                using (var client = new WebClient() { Encoding = Encoding.UTF8 })
                {
                     result = client.DownloadString(postlink.OriginalString);
                }
                //HttpWebRequest myHttpWebRequest = MakeRequest(postlink.OriginalString);
                //myHttpWebRequest.Method = "GET"; // метод GET
                //myHttpWebRequest.Referer = "https://plus.google.com";
                ////получаем ответ и его разбираем...
                //HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                //string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd();
                //myHttpWebResponse.Close();
                //
                if (!String.IsNullOrEmpty(result))
                {
                    MatchCollection mc = rComments.Matches(result);
                    if (mc.Count > 0)
                    {
                        //ВАЖНО, ЧТО КОММЕНТАРИИ У НАС УДВОЕНЫ, то есть надо сократить результат в 2 раза
                        ps.Comments = mc.Count / 2;
                        //теперь переберем их на наличие уникальных
                        var oUniq = new HashSet<string>();
                        foreach (Match match in mc)
                        {
                            oUniq.Add(match.Groups[1].Value);
                        }
                        ps.Commenters = oUniq.Count;
                    }
                    int temp = 0;
                    Match m = rPlusedTotal.Match(result);
                    if (m.Success)
                    {
                        if (int.TryParse(m.Groups[1].Value, out temp))
                        {
                            ps.Views += temp;
                        }
                    }

                    MatchCollection mc2 = rPlusedComments.Matches(result);
                    if (mc2.Count > 0)
                    {
                        //int.TryParse(mc2[0].Groups[1].Value, out ps.Likes);
                        foreach (Match match in mc2)
                        {
                            if (int.TryParse(match.Groups[1].Value, out temp))
                            {
                                ps.Views += temp;
                            }
                        }
                        //if (mc2.Count == 3)//лайки, ссылки, комменты
                        //{
                        //    int.TryParse(mc2[1].Groups[1].Value, out ps.Links);
                        //}
                    }

                    MatchCollection mc3 = rLinks.Matches(result);
                    if (mc3.Count == 3)//есть и комменты и ссылки и шары
                    {
                        int.TryParse(mc3.Cast<Match>().Last().Groups[1].Value, out ps.Links);
                    }

                    //теперь просто оценим число просмотров
                    ps.Views = ps.Views * 3 + ps.Comments * 4 + ps.Links * 10;
                    //грубая оценка
                    if (ps.Views > 10000) ps.Views = 10000;
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine("Ошибка загрузки статистики: " + e1.Message);
            }
            return ps;
        }

        /// <summary>
        /// Получение аватарки по имени
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public override string ExtractAvatar(string userName, BlogType bt)
        {
            string sRet = String.Empty;
            try
            {
                if (userName.Contains("+"))
                {
                    sRet = GetUser(userName).Image.Url;//через уникальное имя запрос
                }
                else
                {
                    var rAvatar = new Regex(@"oid\W+" + userName + @"[^<]+<img[^>]+?src\W+([^""']+photo.jpg)",
                        Regexoptions);
                    HttpWebRequest myHttpWebRequest = MakeRequest(GetBlogLink(userName, bt) + "/about");
                    myHttpWebRequest.Method = "GET"; // метод GET
                    myHttpWebRequest.Referer = "https://plus.google.com";
                    HttpWebResponse myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                    string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd();
                    myHttpWebResponse.Close();
                    //
                    Match mc = rAvatar.Match(result);
                    if (mc.Success)
                    {
                        sRet = Common.FixHttp(mc.Groups[1].Value.Replace("https:", "http:")) + "?sz=50";
                    }
                    else
                    {
                        //обращаемся к API
                        sRet = GetUser(userName).Image.Url;
                    }
                }
            }catch(Exception e1)
            {
                Debug.WriteLine(e1.Message);
            }
            return sRet;
        }

        /// <summary>
        /// Получение списка друзей для выбранного аккаунта
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public Dictionary<string, string[]> GetFriendsList(string userName)
        {
            var sRet = new Dictionary<string, string[]>();
            try
            {
                string rLinkTo = "https://plus.google.com/_/socialgraph/lookup/incoming/?o=%5Bnull%2Cnull%2C%22" +
                                 userName + "%22%5D&n=20000&_reqid=648889&rt=j";
                

                HttpWebRequest myHttpWebRequest = MakeRequest(rLinkTo);
                myHttpWebRequest.Method = "GET"; // метод GET
                myHttpWebRequest.Referer = "https://plus.google.com";
                var myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd();
                myHttpWebResponse.Close();
                //
                MatchCollection mc = rData.Matches(result);
                if(mc.Count>0)
                {
                    foreach (Match match in mc)
                    {
                        sRet.Add(match.Groups[1].Value,match.Groups[2].Value.Split(new []{','},StringSplitOptions.RemoveEmptyEntries));
                        sRet[match.Groups[1].Value][0] = match.Groups[3].Value;//сразу вставим имя без кавычек
                    }
                }   
            }
            catch (Exception e1)
            {
                Debug.WriteLine(e1.Message);
            }
            return sRet;
        }

        /// <summary>
        /// Сервис получение данных в виде RSS
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="firsttime">первое обращение для рекурсивного вызова</param>
        /// <returns></returns>
        public RssDocument GetRss(string userName, bool firsttime=true)
        {
            RssDocument oRet = null;
            try
            {
                if (APIkey == null) throw new ArgumentNullException("APIkey");
                if (APIkey.Length == 0) throw new ArgumentOutOfRangeException("APIkey");

                oRet = new RssDocument
                {
                    Version = "2.0",
                    Channel = new RssChannel
                    {
                        Title = "Error",
                        Generator = "BlogsAPI",
                        itemsPerPage = 20,
                        Link = GetBlogLink(userName),
                        WebMaster = "topbot@yandex.ru",
                        Items = new List<RssItemYandex>(0),
                        LastBuildDate = DateTime.Now.ToString(),
                    }
                };

                string requesturl = String.Format(
                    "https://www.googleapis.com/plus/v1/people/{1}/activities/public?alt=json&maxResults=25&pp=1&key={0}",
                    APIkey[firsttime ? 0 : 1], userName);//можно использовать с именами типа +AntonNossik
                string reply = PerformRequest(requesturl);
                var userActivity = JsonConvert.DeserializeObject<ActivityFeed>(reply);
                //
                oRet.Channel.Title = userActivity.Title;

                if (userActivity.Error != null)
                {
                    throw new Exception(userActivity.Error.Message + " : " + userActivity.Error.Code);
                }
                if (userActivity.Items.Count > 0)
                {
                    oRet.Channel.LastBuildDate = userActivity.Updated.Value.ToString("s");
                    foreach (Activity activity in userActivity.Items)
                    {
                        var item = new RssItemYandex
                        {
                            Link = activity.Url,
                            Description = activity.Object__.Content,
                            Guid = new RssGuid { Text = activity.Id },
                            PubDateParsed = activity.Published.Value
                        };
                        if (activity.Object__ != null &&
                            activity.Object__.Attachments != null &&
                            activity.Object__.Attachments.Count > 0)
                        {
                            item.Title = activity.Object__.Attachments[0].DisplayName;
                            if (!String.IsNullOrEmpty(item.Title) && item.Title.Length > 200)
                            {
                                item.Title = item.Title.Substring(0, 200);
                                var parts = item.Title.Split(new[] { '.', '!', '?' }, StringSplitOptions.RemoveEmptyEntries);
                                if (parts.Length > 1)
                                {
                                    item.Title = parts[0] + item.Title.Substring(parts[0].Length + 1, 1);//добавляем разделительный знак препинания
                                }
                            }
                            switch (activity.Object__.Attachments[0].ObjectType)
                            {
                                case "photo":
                                    item.Description += activity.Object__.Attachments[0].Content;
                                    //activity.Object__.Attachments[0].FullImage.Url - должен быть не нул
                                    item.Description += String.Format("<br/><a href='{0}'><img alt='{1}' src='{2}'></a>",
                                        activity.Object__.Attachments[0].Url ?? activity.Object__.Attachments[0].FullImage.Url,
                                        (activity.Object__.Attachments[0].Content ?? "").Replace("'", ""),
                                        activity.Object__.Attachments[0].FullImage.Url);
                                    item.MediaThumbnail = new Media
                                    {
                                        type = activity.Object__.Attachments[0].Content,
                                        url = activity.Object__.Attachments[0].Image.Url
                                    };
                                    break;
                                case "album":
                                    var att = activity.Object__.Attachments[0];
                                    var image = att.Thumbnails.FirstOrDefault();
                                    if (image != null)
                                    {
                                        item.Description +=
                                            String.Format("<br/><a href='{0}'><img alt='{1}' src='{2}'></a>",
                                                att.Url,
                                                image.Description,
                                                image.Image.Url);
                                        if (item.MediaThumbnail == null && image.Image.Url != null)
                                        {
                                            item.MediaThumbnail = new Media
                                            {
                                                type = image.Image.Type,
                                                url = image.Image.Url
                                            };
                                        }
                                    }
                                    break;
                                case "photo-album":
                                    foreach (var data in activity.Object__.Attachments)
                                    {
                                        if (data != null && data.FullImage != null)
                                        {
                                            item.Description += String.Format("<br/><a href='{0}'><img alt='{1}' src='{2}'></a>",
                                            data.Url ?? activity.Object__.Attachments[0].FullImage.Url,
                                            (data.Content ?? "").Replace("'", ""),
                                            data.FullImage.Url);

                                            if (item.MediaThumbnail == null && data.Image != null)
                                            {
                                                item.MediaThumbnail = new Media
                                                {
                                                    type = data.Content,
                                                    url = data.Image.Url
                                                };
                                            }
                                        }
                                    }
                                    break;
                                case "video":
                                    YouTube yt = new YouTube();
                                    string code;
                                    if (yt.ValidateLink(activity.Object__.Attachments[0].Url, out code))
                                    {
                                        activity.Object__.Attachments[0].Url = YouTube.GetYoutubeCanonical(code);
                                        //и превьюшка
                                        if (item.MediaThumbnail == null)
                                        {
                                            item.MediaThumbnail = new Media
                                            {
                                                category = "video",
                                                type = "application/x-shockwave-flash",
                                                url = activity.Object__.Attachments[0].Url,
                                                thumbnail = new Thumbnail() { url = String.Format("https://img.youtube.com/vi/{0}/mqdefault.jpg", code) }
                                            };
                                        }
                                    }
                                    //кстати есть еще картинка в .Image, но она одна, а с ютуба мы можем вытащить целых 3
                                    //Ссылка на ютуб обязательно вставлять в явном виде, чтобы Short получился как надо и сформировались превьюшки
                                    item.Description += " <a href='" + activity.Object__.Attachments[0].Url + "' >" + (activity.Object__.Attachments[0].DisplayName ?? activity.Object__.Attachments[0].Content) + "</a>";
                                    //проверка того, что это youtube
                                    break;
                                default:
                                case "article":
                                    item.Description += " <a href='" + activity.Object__.Attachments[0].Url + "' >" + (activity.Object__.Attachments[0].Content ?? activity.Object__.Attachments[0].DisplayName) + "</a>";
                                    break;
                            }
                        }
                        else if (String.IsNullOrEmpty(item.Description))
                        {
                            item.Description = activity.Object__.Url;
                        }
                        if (activity.Verb == "post" && String.IsNullOrEmpty(oRet.Channel.Copyright))
                        {
                            oRet.Channel.Copyright = activity.Actor.DisplayName;
                        }
                        if (activity.Object__.Replies.TotalItems.HasValue)
                        {
                            item.ReplyCount = item.YaComments = (int)activity.Object__.Replies.TotalItems.Value;
                        }
                        if (activity.Object__.Resharers.TotalItems.HasValue)
                        {
                            item.YaLinks = (int)activity.Object__.Resharers.TotalItems.Value;
                        }
                        if (activity.Object__.Plusoners.TotalItems.HasValue)
                        {
                            item.YaVisits24 = (int)activity.Object__.Plusoners.TotalItems.Value;
                        }
                        oRet.Channel.Items.Add(item);
                    }
                }
            }
            //catch (WebException e1)//ошибка сети или еще что
            //{
            //    Debug.WriteLine(e1);
            //    if (firsttime && e1.Response != null && ((HttpWebResponse)e1.Response).StatusCode == HttpStatusCode.Forbidden
            //        && APIkey.Length > 1)//есть 2 ключа
            //    {
            //        //Thread.Sleep(30000); //так как превысили лимит, то надо 30 секунд куковать
            //        oRet = GetRss(userName, false);//вторая попытка
            //    }
            //}
            catch (Exception e2)
            {
                Debug.WriteLine(e2);
                oRet.Channel.Title = e2.Message;
            }
            return oRet;
        }

        /// <summary>
        /// Получение информации о конкретном блогере через API
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public Person GetUser(string userName)
        {
            Person ret = null;
            try
            {
                //либо номер, либо с плюсом
                userName = Regex.Match(userName, @"^[0-9]+$").Success ? userName : "+" + userName.TrimStart('+');
                var apiHelper = new GooglePlusAPIHelper(userName, APIkey[0]);
                ret = apiHelper.GetPerson();
            }
            catch (Exception e1)
            {
                Debug.Write(e1);
            }
            return ret;
        }

        /// <summary>
        /// Поиск блогеров через API
        /// </summary>
        /// <param name="phrase">фраза</param>
        /// <returns></returns>
        public IList<Person> Search(string phrase)
        {
            try
            {
                var apiHelper = new GooglePlusAPIHelper("", APIkey[0]);
                var feed = apiHelper.SearchPeople(phrase);
                return feed.Items;
            }
            catch (Exception e1)
            {
                Debug.Write(e1);
            }
            return null;
        }

        #endregion

        #region ILike

        public Dictionary<string, int> GetLikes(Uri Link)
        {
            var oRet = new Dictionary<string, int>();
            try
            {
                HttpWebRequest myHttpWebRequest;
                HttpWebResponse myHttpWebResponse;
                string faceLink = String.Format(
                    "https://plusone.google.com/u/0/_/+1/fastbutton?count=true&url={0}",
                    HttpUtility.UrlEncode(Link.OriginalString.Replace("https://","http://")));
                myHttpWebRequest = MakeRequest(faceLink);
                myHttpWebRequest.Method = "GET"; // метод GET
                myHttpWebRequest.Referer = "http://plusone.google.com";
                //получаем ответ и его разбираем...
                myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd();
                myHttpWebResponse.Close();
                Match m = new Regex(@"<div[^>]+?aggregateCount[^>]+>\D*(\d+)\D").Match(result);
                if (m.Success)
                {
                    oRet.Add("count", int.Parse(m.Groups[1].Value));
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine(e1);
            }
            return oRet;
        }

        #endregion

        /// <summary>
        /// Получение имени города по координатам
        /// </summary>
        /// <param name="lat">широта</param>
        /// <param name="lng">долгота</param>
        /// <param name="language">язык результата</param>
        /// <param name="firsttime">две попытки будут для запроса города</param>
        /// <returns>Имя города</returns>
        public GeoResult GetCityNameFromCoords(double lat, double lng, CultureInfo language = null)
        {
            GeoGoogle gg = new GeoGoogle();
            return gg.GetCityFromCoords(lat, lng, language);
        }

        /// <summary>
        /// Получение координат по адресу
        /// </summary>
        /// <param name="address">текстовое описание места</param>
        /// <returns>Координаты</returns>
        public Location GetCoordsFromAddress(string address)
        {
            Location loc = null;
            //http://maps.googleapis.com/maps/api/geocode/json?address=%D0%A1%D1%82%D0%B0%D0%B2%D1%80%D0%BE%D0%BF%D0%BE%D0%BB%D1%8C%D1%81%D0%BA%D0%B8%D0%B9%20%D0%BA%D1%80%D0%B0%D0%B9%20%D0%B3.%20%D0%9D%D0%B5%D0%B2%D0%B8%D0%BD%D0%BD%D0%BE%D0%BC%D1%8B%D1%81%D1%81%D0%BA
            try
            {
                if (APIkey == null) throw new ArgumentNullException("APIkey");
                if (APIkey.Length == 0) throw new ArgumentOutOfRangeException("APIkey");
                /////////////////////////////
                string requesturl = String.Format(
                        "https://maps.googleapis.com/maps/api/geocode/json?address={0}",
    HttpUtility.UrlEncode(address), APIkey[0]);
                string reply = PerformRequest(requesturl);
                var data = JObject.Parse(reply);
                loc = new Location
                {
                    Latitude = data["results"][0]["geometry"]["location"]["lat"].Value<decimal>(),
                    Longitude = data["results"][0]["geometry"]["location"]["lng"].Value<decimal>(),
                    Name = data["results"][0]["formatted_address"].Value<string>(),
                };
            }
            catch (Exception e2)
            {
                //плохо, очень плохо
                Debug.WriteLine(e2.Message);
            }
            return loc;
        }

        /// <summary>
        /// Получение комментариев от видео ютуба
        /// </summary>
        /// <param name="url">просто ссылка на пост</param>
        /// <param name="activityId">"id": "z13qd5zouuebcpauy23tuftwdsylxflvs",</param>
        /// <returns></returns>
        public List<BlogPost> GetComments(Uri url, string activityId, DateTime? fromTime = null)
        {
            List<BlogPost> oRet = new List<BlogPost>();
            try
            {
                if (APIkey == null) throw new ArgumentNullException("APIkey");
                if (APIkey.Length == 0) throw new ArgumentOutOfRangeException("APIkey");
                int maxResults = 500;
                CommentFeed postComments = null;
                do
                {
                    //https://www.googleapis.com/plus/v1/activities/z12uvbnqdovegfivb23djjuazly3vx5uh/comments?maxResults=500&sortOrder=descending&key={YOUR_API_KEY}
                    string requesturl = String.Format(
                        "https://www.googleapis.com/plus/v1/activities/{1}/comments?maxResults={2}&sortOrder=descending&key={0}{3}",
                        APIkey[0], activityId, maxResults,
                        postComments==null?"":postComments.NextPageToken//следующая страница
                        );
                    string reply = PerformRequest(requesturl);

                    postComments = JsonConvert.DeserializeObject<CommentFeed>(reply);
                    //получили 500 штук и их нам не хватит(!)
                    foreach (var postComment in postComments.Items)
                    {
                        if (fromTime == null || postComment.Updated.Value >= fromTime)
                        {
                            //добавляем
                            var bp = BlogPost.SimpleLink(url+"#"+postComment.Id);
                            bp.SpecialParam = postComment.Actor.Id;
                            bp.Links = (int)postComment.Plusoners.TotalItems.Value;
                            bp.Published = postComment.Updated.Value;
                            bp.Subject = postComment.Actor.DisplayName;
                            bp.Body = postComment.Object__.Content;
                            oRet.Add(bp);
                        }
                        else if (postComment.Updated.Value < fromTime)
                        {
                            break; //закончили с этим делом
                        }
                    }
                } while (postComments.Items.Count == maxResults);
            }
            catch (Exception e1)
            {
                Debug.Write(e1);
            }
            return oRet;
        }
    }
}
